import cv2
import datetime
import os
import csv
import math
import numpy as np
try:
    from . import pose_recognition as pr
except Exception as a:   # Exception所有异常    代码错了就执行
    import pose_recognition as pr


def now_time():
        now  = datetime.datetime.now()
        nownow = now.strftime("%Y-%m-%d %H%M")
        return nownow


    # 切割图像
def slicing_photo(self,side,image):
    """
    slicing_photo函数可以  将图片垂直切割,根据side变量选择返回左边、右边或完整的图片
    :param self:
    :param side:选择需要返回的边,0-完整  1-左边  2-右边
    :return:
    """
    # 获取当前帧的数据
    height, width = image.shape[:2]
    # 将图片垂直居中切割
    halp_width = width // 2
    
    # 判断返回哪一边的图片
    if side == 1:
        left_photo = image[:,:halp_width]
        return left_photo
    
    elif side == 2:
        right_photo = image[:,halp_width:]
        return right_photo
    
    elif side == 0:
        return image
    

def normalized_to_pixel(self,value):
        """
        normalized_to_pixel函数可以接收三个参数,并获取索引值的归一化坐标，并将归一化坐标转换成像素坐标
        :param results:当前帧的关键点信息
        :param self:
        :param value:需要获取的关键点索引值
        :return:返回像素坐标(元组)
        """
        landmark = self.results.pose_landmarks.landmark[value]
        normalized_coord = (landmark.x,landmark.y)
        pixel_coord = ((int(normalized_coord[0]*self.frame_width), int(normalized_coord[1]*self.frame_height)))
        return pixel_coord, normalized_coord


# 两点距离公式
def Two_point_distance(one_point,two_point):
    """
    Two_point_distance函数可以接收两个参数(坐标点),并将两个坐标点的距离返回  ---二维
    :param one_point:第一个坐标点(x, y)
    :param two_point:第二个坐标点(x, y)
    :return: 返回两点之间距离的计算结果
    """
    result_distance = math.sqrt((two_point[0]-one_point[0])**2+(two_point[1]-one_point[1])**2)
    return result_distance


# 初始化三个csv文件
def setup_csv():
    """
    setup_csv函数可以在此py文件目录下新建一个data_csv文件夹,并初始化三个csv文件( AllLandmarks{nowtime}.csv  NeedData{nowtime}.csv  AttackData{nowtime}.csv)
    :param self:
    :return:
    """
# 创建 data_csv 文件夹
    # 获取当前时间
    nowtime = now_time()

    # 获取当前文件的绝对路径
    current_path = os.path.abspath(__file__)
    # 获取当前文件所在的目录
    script_dirt = os.path.dirname(current_path)
    # 定义新文件名字
    new_file_name = "data_csv"
    new_file_path = os.path.join(script_dirt,new_file_name)  

    try:
        os.makedirs(new_file_path,exist_ok=True)
        # print(f"文件夹'{new_file_path}'创建成功")
    except OSError as error:
        print(f"创建文件夹出错：{error}")

#生成三个csv路径  all_landmarks_csv_path    all_NeedData_csv_path   all_AttackData_csv_path
    all_landmarks_csv_path = f"{new_file_path}/AllLandmarks{nowtime}.csv" 
    all_NeedData_csv_path = f"{new_file_path}/NeedData{nowtime}.csv"  
    all_AttackData_csv_path = f"{new_file_path}/AttackData{nowtime}.csv" 

    # 新建三个csv文件
    csv_AllLandmarks = open(all_landmarks_csv_path,'w',newline='') # 打开csv文件
    csv_NeedData = open(all_NeedData_csv_path,'w',newline='') # 打开csv文件
    csv_AttackData = open(all_AttackData_csv_path,'w',newline='') # 打开csv文件

    # 设置AllLandmarks.csv页眉
    csv_W_AllLandmarks = csv.writer(csv_AllLandmarks)
    csv_W_AllLandmarks.writerow(['当前帧率','关键点','X','Y'])

    # 设置NeedData.csv页眉
    csv_W_NeedData = csv.writer(csv_NeedData)  #  帧率 左肩坐标 右肩坐标 左臀坐标 右臀坐标 左膝盖角度 右膝盖角度 左手臂角度
    csv_W_NeedData.writerow(['当前帧率','左肩坐标','右肩坐标','左臀坐标','右臀坐标','左膝盖角度','右膝盖角度','右手肘角度']) # 坐标均为坐标元组
    
    # 设置AttackData.csv页眉
    
    csv_W_AttackData = csv.writer(csv_AttackData)   # 攻击次数  右手臂角度  右脚与地面角度 左脚与地面角度 前脚移动距离
    csv_W_AttackData.writerow(['攻击次数','右手肘角度','右脚夹角','左脚夹角','前脚移动距离'])
    # return csv_W_AllLandmarks,csv_W_NeedData,csv_W_AttackData
    return [csv_AllLandmarks,
            csv_NeedData,
            csv_AttackData,
            csv_W_AllLandmarks,
            csv_W_NeedData,
            csv_W_AttackData]


def cal_ang(self,value1, value2, value3):

    """
    根据三点坐标计算夹角
    :param value1: 第一个点的索引值
    :param value2: 第二个点的索引值
    :param value3: 第三个点的索引值，（如果为负一，没有实体点，将自动创建辅助点）
    :return: 返回任意角的夹角值,这里只是返回点2的夹角
    """
    
    # 判断1、2索引值是否有效（0~32）
    if 0 <= value1 <33 and 0 <= value2 <33:
            point_1 = normalized_to_pixel(self,value1)[0]  # 获取第一个点的像素坐标
            point_2 = normalized_to_pixel(self,value2)[0]  # 获取第二个点的像素坐标
    else:
            print("计算角度的关键点查找不到")
            return False
    
    # 判断第三个点是否有效
    if 0 <= value3 <33:
            point_3 = normalized_to_pixel(self,value3)[0]  # 获取第三个点的像素坐标
    # 如果value3为负一，为第三个角设定辅助点        
    elif value3 == -1:
            point_3 = (point_2[0]+5,point_2[1])         # 创建一个虚拟点，作为第三个点
    else:
            print("计算角度的第三点溢出")
            return False
    
    pA = math.sqrt(
        (point_2[0] - point_3[0]) * (point_2[0] - point_3[0]) + (point_2[1] - point_3[1]) * (point_2[1] - point_3[1]))
    pB = math.sqrt(
        (point_1[0] - point_3[0]) * (point_1[0] - point_3[0]) + (point_1[1] - point_3[1]) * (point_1[1] - point_3[1]))
    pC = math.sqrt(
        (point_1[0] - point_2[0]) * (point_1[0] - point_2[0]) + (point_1[1] - point_2[1]) * (point_1[1] - point_2[1]))
    
    angleA = math.degrees(math.acos((pA * pA - pB * pB - pC * pC) / (-2 * pB * pC)))
    angleB = math.degrees(math.acos((pB * pB - pA * pA - pC * pC) / (-2 * pA * pC)))
    angleC = math.degrees(math.acos((pC * pC - pA * pA - pB * pB) / (-2 * pA * pB)))
    # 左右脚踝与地面夹角，只取小角
    if value2 in [27,28] and angleB >90:
            angleB = 180-angleB
    # print(type(angleB))

    # 格式化输出
    angleB = float(format(angleB,'.2f'))
    return angleB


def hight_pixel_rstio(self):
    """
    hight_pixel_rstio 函数可以接收两个参数,并获取鼻子、右臀、右膝盖、右脚踝四个关键点的像素坐标，计算人体像素身高，最后用人体实际身高/人体像素身高，得到像素比例因子
    :param self:
    :param results: 当前帧的姿态检测结果
    :return: 返回像素比例因子
    """
    nose_pixel = normalized_to_pixel(self,0)[0]  # 鼻子像素点
    right_hip_pixel = normalized_to_pixel(self,24)[0]  # 右臀像素点
    right_knee_pixel = normalized_to_pixel(self,26)[0]  # 右膝盖像素点
    right_ankle_pixel = normalized_to_pixel(self,28)[0] # 右脚踝像素点

    nose_to_hip = Two_point_distance(nose_pixel,right_hip_pixel)  # 鼻子到右臀距离
    hip_to_knee = Two_point_distance(right_hip_pixel,right_knee_pixel) # 右臀到右膝盖距离
    knee_to_ankle = Two_point_distance(right_knee_pixel,right_ankle_pixel) # 右膝盖到右脚踝

    human_height_pixel = nose_to_hip + hip_to_knee + knee_to_ankle  # 像素点身高
    pixel_ratio = self.height_real / human_height_pixel # 人体比例因子
    return pixel_ratio,human_height_pixel




def read_standard_landmarks(file_path):
    with open(file_path, 'r') as file:
        reader = csv.reader(file)
        next(reader)
        standard_landmarks = {int(rows[1]): (float(rows[2]), float(rows[3])) for rows in reader}
        # print(standard_landmarks)
        
    return standard_landmarks


# 比较关键点
def compare_landmarks(standard_landmarks, current_landmarks, threshold):
    # print("分界线")
    count = 0

    need_coord = [11,12,13,14,15,16,23,24,25,26,27,28]
    # 获取标准数据的每一组键值对
    # for key, standard_point in standard_landmarks.items():
    for key in need_coord:
        # print(f"key{key},{standard_point}")
        standard_point = standard_landmarks.get(key)
        # 获取当前关键点的对应键值对
        current_point = current_landmarks.get(key)
        # print(f"current:{current_point}")
        
        # if current_point and key in need_coord:

            # 计算距离
        distance = Two_point_distance(standard_point, current_point)
        # if distance > threshold:
        #     print(f"关键点 {key} 偏差过大，距离: {distance:.2f}")
        # else:
        #         count += 1
        #         print(f"关键点 {key} 标准，距离: {distance:.2f}")

        if 0 <= distance <= threshold:
             count += 1
        # else:
        #     print(f"关键点 {key} 未检测到")
        # print(count)

        

    if count in [12]:
        print("标准的弓步") 
    
    if count in [10,11]:
        print("较为标准的弓步")

    if count in [8,9]:
        print("需要改进")

        # if count == 12:
        #     print("标准的弓步")
        # elif count >= 10:
        #     print("较为标准的弓步")
        # elif count >= 8:
        #     print("需要改进的弓步")



        # if count >= 8
    # print("----------")


def is_similar_frame(prev_frame, current_frame, threshold):
    # 计算两帧之间的差异
    diff = np.linalg.norm(np.array(prev_frame) - np.array(current_frame))
    # 如果差异小于阈值，则认为两帧相似
    return diff < threshold

def select_keyframes(frames, threshold):
    keyframes = [frames[0]]  # 将第一帧作为关键帧
    for i in range(1, len(frames)):
        if is_similar_frame(keyframes[-1], frames[i], threshold):
            continue  # 如果当前帧与上一个关键帧相似，则跳过
        keyframes.append(frames[i])  # 将当前帧添加为关键帧
    return keyframes